﻿using System.Collections.ObjectModel;
using System.Linq;

namespace System.Collections.Specialized
{

	//
	//	public class NotifyCollectionChangedEventArgs : EventArgs
	//	{
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a System.Collections.Specialized.NotifyCollectionChangedAction.Reset
	//     change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This must be set to System.Collections.Specialized.NotifyCollectionChangedAction.Reset.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action)
	//		{
	//			
	//		}
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a multi-item change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can be set to System.Collections.Specialized.NotifyCollectionChangedAction.Reset,
	//     System.Collections.Specialized.NotifyCollectionChangedAction.Add, or System.Collections.Specialized.NotifyCollectionChangedAction.Remove.
	//
	//   changedItems:
	//     The items that are affected by the change.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a one-item change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can be set to System.Collections.Specialized.NotifyCollectionChangedAction.Reset,
	//     System.Collections.Specialized.NotifyCollectionChangedAction.Add, or System.Collections.Specialized.NotifyCollectionChangedAction.Remove.
	//
	//   changedItem:
	//     The item that is affected by the change.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Reset, Add, or Remove, or if action is Reset and changedItems
	//     is not null.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a multi-item System.Collections.Specialized.NotifyCollectionChangedAction.Replace
	//     change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can only be set to System.Collections.Specialized.NotifyCollectionChangedAction.Replace.
	//
	//   newItems:
	//     The new items that are replacing the original items.
	//
	//   oldItems:
	//     The original items that are replaced.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Replace.
	//
	//   System.ArgumentNullException:
	//     If oldItems or newItems is null.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a multi-item change or a System.Collections.Specialized.NotifyCollectionChangedAction.Reset
	//     change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can be set to System.Collections.Specialized.NotifyCollectionChangedAction.Reset,
	//     System.Collections.Specialized.NotifyCollectionChangedAction.Add, or System.Collections.Specialized.NotifyCollectionChangedAction.Remove.
	//
	//   changedItems:
	//     The items affected by the change.
	//
	//   startingIndex:
	//     The index where the change occurred.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Reset, Add, or Remove, if action is Reset and either changedItems
	//     is not null or startingIndex is not -1, or if action is Add or Remove and
	//     startingIndex is less than -1.
	//
	//   System.ArgumentNullException:
	//     If action is Add or Remove and changedItems is null.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int startingIndex);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a one-item change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can be set to System.Collections.Specialized.NotifyCollectionChangedAction.Reset,
	//     System.Collections.Specialized.NotifyCollectionChangedAction.Add, or System.Collections.Specialized.NotifyCollectionChangedAction.Remove.
	//
	//   changedItem:
	//     The item that is affected by the change.
	//
	//   index:
	//     The index where the change occurred.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Reset, Add, or Remove, or if action is Reset and either
	//     changedItems is not null or index is not -1.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a one-item System.Collections.Specialized.NotifyCollectionChangedAction.Replace
	//     change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can only be set to System.Collections.Specialized.NotifyCollectionChangedAction.Replace.
	//
	//   newItem:
	//     The new item that is replacing the original item.
	//
	//   oldItem:
	//     The original item that is replaced.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Replace.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a multi-item System.Collections.Specialized.NotifyCollectionChangedAction.Replace
	//     change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can only be set to System.Collections.Specialized.NotifyCollectionChangedAction.Replace.
	//
	//   newItems:
	//     The new items that are replacing the original items.
	//
	//   oldItems:
	//     The original items that are replaced.
	//
	//   startingIndex:
	//     The index of the first item of the items that are being replaced.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Replace.
	//
	//   System.ArgumentNullException:
	//     If oldItems or newItems is null.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a multi-item System.Collections.Specialized.NotifyCollectionChangedAction.Move
	//     change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can only be set to System.Collections.Specialized.NotifyCollectionChangedAction.Move.
	//
	//   changedItems:
	//     The items affected by the change.
	//
	//   index:
	//     The new index for the changed items.
	//
	//   oldIndex:
	//     The old index for the changed items.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Move or index is less than 0.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a multi-item System.Collections.Specialized.NotifyCollectionChangedAction.Move
	//     change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can only be set to System.Collections.Specialized.NotifyCollectionChangedAction.Move.
	//
	//   changedItem:
	//     The item affected by the change.
	//
	//   index:
	//     The new index for the changed item.
	//
	//   oldIndex:
	//     The old index for the changed item.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Move or index is less than 0.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex);
	//
	// Summary:
	//     Initializes a new instance of the System.Collections.Specialized.NotifyCollectionChangedEventArgs
	//     class that describes a one-item System.Collections.Specialized.NotifyCollectionChangedAction.Replace
	//     change.
	//
	// Parameters:
	//   action:
	//     The action that caused the event. This can be set to System.Collections.Specialized.NotifyCollectionChangedAction.Replace.
	//
	//   newItem:
	//     The new item that is replacing the original item.
	//
	//   oldItem:
	//     The original item that is replaced.
	//
	//   index:
	//     The index of the item being replaced.
	//
	// Exceptions:
	//   System.ArgumentException:
	//     If action is not Replace.
	//		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem, int index);
	//
	// Summary:
	//     Gets the action that caused the event.
	//
	// Returns:
	//     A System.Collections.Specialized.NotifyCollectionChangedAction value that
	//     describes the action that caused the event.
	//		public NotifyCollectionChangedAction Action { get; }
	//
	// Summary:
	//     Gets the list of new items involved in the change.
	//
	// Returns:
	//     The list of new items involved in the change.
	//		public IList NewItems { get; }
	//
	// Summary:
	//     Gets the index at which the change occurred.
	//
	// Returns:
	//     The zero-based index at which the change occurred.
	//		public int NewStartingIndex { get; }
	//
	// Summary:
	//     Gets the list of items affected by a System.Collections.Specialized.NotifyCollectionChangedAction.Replace,
	//     Remove, or Move action.
	//
	// Returns:
	//     The list of items affected by a System.Collections.Specialized.NotifyCollectionChangedAction.Replace,
	//     Remove, or Move action.
	//		public IList OldItems { get; }
	//
	// Summary:
	//     Gets the index at which a System.Collections.Specialized.NotifyCollectionChangedAction.Move,
	//     Remove, ore Replace action occurred.
	//
	// Returns:
	//     The zero-based index at which a System.Collections.Specialized.NotifyCollectionChangedAction.Move,
	//     Remove, or Replace action occurred.
	//		public int OldStartingIndex { get; }
	//	}7


	//[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
	public class NotifyCollectionChangedEventArgs : EventArgs
	{
		// Fields
		private NotifyCollectionChangedAction _action;
		private IList _newItems;
		private int _newStartingIndex;
		private IList _oldItems;
		private int _oldStartingIndex;

		// Methods
		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (action != NotifyCollectionChangedAction.Reset)
			{
				throw new ArgumentException(SR.GetString("WrongActionForCtor", new object[] { NotifyCollectionChangedAction.Reset }), "action");
			}
			this.InitializeAdd(action, null, -1);
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset))
			{
				throw new ArgumentException(SR.GetString("MustBeResetAddOrRemoveActionForCtor"), "action");
			}
			if (action == NotifyCollectionChangedAction.Reset)
			{
				if (changedItems != null)
				{
					throw new ArgumentException(SR.GetString("ResetActionRequiresNullItem"), "action");
				}
				this.InitializeAdd(action, null, -1);
			}
			else
			{
				if (changedItems == null)
				{
					throw new ArgumentNullException("changedItems");
				}
				this.InitializeAddOrRemove(action, changedItems, -1);
			}
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset))
			{
				throw new ArgumentException(SR.GetString("MustBeResetAddOrRemoveActionForCtor"), "action");
			}
			if (action == NotifyCollectionChangedAction.Reset)
			{
				if (changedItem != null)
				{
					throw new ArgumentException(SR.GetString("ResetActionRequiresNullItem"), "action");
				}
				this.InitializeAdd(action, null, -1);
			}
			else
			{
				this.InitializeAddOrRemove(action, new object[] { changedItem }, -1);
			}
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (action != NotifyCollectionChangedAction.Replace)
			{
				throw new ArgumentException(SR.GetString("WrongActionForCtor", new object[] { NotifyCollectionChangedAction.Replace }), "action");
			}
			if (newItems == null)
			{
				throw new ArgumentNullException("newItems");
			}
			if (oldItems == null)
			{
				throw new ArgumentNullException("oldItems");
			}
			this.InitializeMoveOrReplace(action, newItems, oldItems, -1, -1);
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset))
			{
				throw new ArgumentException(SR.GetString("MustBeResetAddOrRemoveActionForCtor"), "action");
			}
			if (action == NotifyCollectionChangedAction.Reset)
			{
				if (changedItems != null)
				{
					throw new ArgumentException(SR.GetString("ResetActionRequiresNullItem"), "action");
				}
				if (startingIndex != -1)
				{
					throw new ArgumentException(SR.GetString("ResetActionRequiresIndexMinus1"), "action");
				}
				this.InitializeAdd(action, null, -1);
			}
			else
			{
				if (changedItems == null)
				{
					throw new ArgumentNullException("changedItems");
				}
				if (startingIndex < -1)
				{
					throw new ArgumentException(SR.GetString("IndexCannotBeNegative"), "startingIndex");
				}
				this.InitializeAddOrRemove(action, changedItems, startingIndex);
			}
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)) && (action != NotifyCollectionChangedAction.Reset))
			{
				throw new ArgumentException(SR.GetString("MustBeResetAddOrRemoveActionForCtor"), "action");
			}
			if (action == NotifyCollectionChangedAction.Reset)
			{
				if (changedItem != null)
				{
					throw new ArgumentException(SR.GetString("ResetActionRequiresNullItem"), "action");
				}
				if (index != -1)
				{
					throw new ArgumentException(SR.GetString("ResetActionRequiresIndexMinus1"), "action");
				}
				this.InitializeAdd(action, null, -1);
			}
			else
			{
				this.InitializeAddOrRemove(action, new object[] { changedItem }, index);
			}
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (action != NotifyCollectionChangedAction.Replace)
			{
				throw new ArgumentException(SR.GetString("WrongActionForCtor", new object[] { NotifyCollectionChangedAction.Replace }), "action");
			}
			this.InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, -1, -1);
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (action != NotifyCollectionChangedAction.Replace)
			{
				throw new ArgumentException(SR.GetString("WrongActionForCtor", new object[] { NotifyCollectionChangedAction.Replace }), "action");
			}
			if (newItems == null)
			{
				throw new ArgumentNullException("newItems");
			}
			if (oldItems == null)
			{
				throw new ArgumentNullException("oldItems");
			}
			this.InitializeMoveOrReplace(action, newItems, oldItems, startingIndex, startingIndex);
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (action != NotifyCollectionChangedAction.Move)
			{
				throw new ArgumentException(SR.GetString("WrongActionForCtor", new object[] { NotifyCollectionChangedAction.Move }), "action");
			}
			if (index < 0)
			{
				throw new ArgumentException(SR.GetString("IndexCannotBeNegative"), "index");
			}
			this.InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (action != NotifyCollectionChangedAction.Move)
			{
				throw new ArgumentException(SR.GetString("WrongActionForCtor", new object[] { NotifyCollectionChangedAction.Move }), "action");
			}
			if (index < 0)
			{
				throw new ArgumentException(SR.GetString("IndexCannotBeNegative"), "index");
			}
			object[] newItems = new object[] { changedItem };
			this.InitializeMoveOrReplace(action, newItems, newItems, index, oldIndex);
		}

		public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem, int index)
		{
			this._newStartingIndex = -1;
			this._oldStartingIndex = -1;
			if (action != NotifyCollectionChangedAction.Replace)
			{
				throw new ArgumentException(SR.GetString("WrongActionForCtor", new object[] { NotifyCollectionChangedAction.Replace }), "action");
			}
			this.InitializeMoveOrReplace(action, new object[] { newItem }, new object[] { oldItem }, index, index);
		}

		private void InitializeAdd(NotifyCollectionChangedAction action, IList newItems, int newStartingIndex)
		{
			this._action = action;
			this._newItems = (newItems == null) ? null : (newItems).Cast<object>().ToArray(); ;
			this._newStartingIndex = newStartingIndex;
		}

		private void InitializeAddOrRemove(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
		{
			if (action == NotifyCollectionChangedAction.Add)
			{
				this.InitializeAdd(action, changedItems, startingIndex);
			}
			else if (action == NotifyCollectionChangedAction.Remove)
			{
				this.InitializeRemove(action, changedItems, startingIndex);
			}
		}

		private void InitializeMoveOrReplace(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex)
		{
			this.InitializeAdd(action, newItems, startingIndex);
			this.InitializeRemove(action, oldItems, oldStartingIndex);
		}

		private void InitializeRemove(NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex)
		{
			this._action = action;
			this._oldItems = (oldItems == null) ? null : oldItems.Cast<object>().ToArray();
			this._oldStartingIndex = oldStartingIndex;
		}

		// Properties
		public NotifyCollectionChangedAction Action
		{
			//[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
			get
			{
				return this._action;
			}
		}

		public IList NewItems
		{
			//[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
			get
			{
				return this._newItems;
			}
		}

		public int NewStartingIndex
		{
			//[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
			get
			{
				return this._newStartingIndex;
			}
		}

		public IList OldItems
		{
			//[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
			get
			{
				return this._oldItems;
			}
		}

		public int OldStartingIndex
		{
			//[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
			get
			{
				return this._oldStartingIndex;
			}
		}
	}
}